package com.core.base.dao;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import com.core.base.searchForm.ISearchForm;
import com.core.base.searchForm.hql.IBaseHQLSearchForm;
import com.core.base.searchForm.support.SimpleSearchFormSupport;
import com.core.page.PagerResult;
import com.core.util.ClassUtil;
import com.core.util.PageBean;

/**
 * 基础DAO
 * 
 * @author pt-chenqw
 *
 * @param <E>
 */
@SuppressWarnings({"unchecked","hiding"})
public class BaseHibernateDao<E> implements BaseIDAO<E> {
	
	protected final Logger log = Logger.getLogger(BaseHibernateDao.class);
	
	private SessionFactory sessionFactory;
	
	private SimpleSearchFormSupport<E> searchFormSupport;
	
	void initSearchFormSupport(){
		if(searchFormSupport == null){
			searchFormSupport = new SimpleSearchFormSupport<>();
		}
		searchFormSupport.setPersistentClass(ClassUtil.getSuperClassGenricType(getClass(), 0));
	}

	public SessionFactory getSessionFactory() {
		return this.sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public Session getSession() {
		return this.sessionFactory.getCurrentSession();
	}

	@Resource(name = "sessionFactory")
	public void setSF(SessionFactory sessionFactory) {
		setSessionFactory(sessionFactory);
	}


	public void save(E entity) {
		getSession().save(entity);
	}

	public void delete(E entity) {
		getSession().delete(entity);
	}


	public void update(E entity) {
		getSession().update(entity);
	}

	public E merge(E entity) {
		return (E) getSession().merge(entity);
	}

	public void clear() {
		getSession().clear();
	}

	public void evict(E entity) {
		getSession().evict(entity);
	}

	protected void setParameter(Map<String, Object> mapParameter, Query query) {
		for (Iterator<String> it = mapParameter.keySet().iterator(); it.hasNext();) {
			String parameterName = (String) it.next();
			Object value = mapParameter.get(parameterName);
			query.setParameter(parameterName, value);
		}
	}

	/**
	 * 根据HQL查询所有记录
	 * @param hql
	 * @return
	 */
	public List<E> findAll(String hql){
		Query query = getSession().createQuery(hql);
		return query.list();
	}
	
	/**
	 * 根据HQL和参数查询列表
	 * @param hql
	 * @param args
	 * @return
	 */
	public List<E> find(String hql,Object...args){
		Query query = getSession().createQuery(hql);
		setParameter(query, args);
		return query.list().size() > 0 ? query.list() : null;
	}
	
	/**
	 * 设置参数
	 * @param query
	 * @param args
	 */
	private void setParameter(Query query, Object...args){
		for (int i = 0; i < args.length; i++) {
			if(args[i] instanceof Integer){
				query.setInteger(i, (int) args[i]);
			}else if(args[i] instanceof String){
				query.setString(i, (String) args[i]);
			}else if(args[i] instanceof Double){
				query.setDouble(i, (double) args[i]);
			}else if(args[i] instanceof Float){
				query.setFloat(i, (float) args[i]);
			}else if(args[i] instanceof Boolean){
				query.setBoolean(i, (boolean) args[i]);
			}else if(args[i] instanceof Date){
				query.setDate(i, (Date) args[i]);
			}else if(args[i] instanceof Long){
				query.setLong(i, (Long) args[i]);
			}
		}
	}
	
	/**
	 * 根据HQL和参数查询唯一一条记录
	 * @param hql
	 * @param args
	 * @return
	 */
	public E findOne(String hql, Object...args){
		Query query = getSession().createQuery(hql);
		setParameter(query, args);
		List<E> lists = query.list();
		return lists.size() > 0 ? lists.get(0) : null;
	}
	
	/**
	 * HQL分页查询
	 * @param hql HQL语句
	 * @param pageNo 下一页
	 * @param pageSize 一页总条数
	 * @param values不定Object数组参数
	 * @return
	 */
	public PageBean<E> findPageByFetchedHql(String hql, int pageNo, int pageSize, Object... values) {
		PageBean<E> retValue = new PageBean<E>();
		Query query = this.getSession().createQuery(hql);
		if (values != null) {
			setParameter(query, values);
		}
		int currentPage = pageNo > 1 ? pageNo : 1;
		retValue.setCurrentPage(currentPage);
		retValue.setPageSize(pageSize);
		ScrollableResults results = query.scroll();
		results.last();
		// 设置总记录数
		retValue.setTotalCount(results.getRowNumber() + 1);
		retValue.resetPageNo();
		List<E> itemList = query.setFirstResult((currentPage - 1) * pageSize).setMaxResults(pageSize).list();
		if (itemList == null) {
			itemList = new ArrayList<E>();
		}
		retValue.setResutls(itemList);    

		return retValue;
	}
	
	@Override
	public Integer countByHql(String hql) {
		Query query = this.getSession().createQuery(hql);
		return (Integer) query.list().get(0);
	}
	
	@Override
	public Integer countByHql(String hql, Object... values) {
		Query query = this.getSession().createQuery(hql);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return (Integer) query.uniqueResult();
	}

	@Override
	public int executeHQL(String hql, Object... values) {
		Query query = this.getSession().createQuery(hql);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query.executeUpdate();
	}

	@Override
	public PagerResult<E> findbyCondition(final Class<?> searchClass,final ISearchForm searchForm) {
		initSearchFormSupport();
		Session session = getSession();
		return searchFormSupport.findBySearchForm(searchClass, session, searchForm); 
	}

	@Override
	public PagerResult<E> findbyHQLCondition(Class<?> searchClass,
			IBaseHQLSearchForm searchForm) {
		initSearchFormSupport();
		Session session = getSession();
		return searchFormSupport.searchByHQLSearchForm(searchClass, session, searchForm);
	}

	@Override
	public void deleteBatch(List<E> entities) {
		for (E e : entities) {
			delete(e);
		}
	}
	
	private <E> List<E> findObject(String hql,Object[] values){
		List<E> lst = null;
		Query queryObject = this.getSession().createQuery(hql);
		if (values != null) {
			setParameter(queryObject, values);
		}
		lst = queryObject.list();
		return (List<E>)lst;
	}
	
	public List<Object[]> findByHQL(String hql,Object[] values){
		return findObject(hql, values);
	}

}
